package br.ufmg.ubicomp.droidguide.eventservice.management;

import java.util.Calendar;
import java.util.Collection;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.logging.Logger;

import br.ufmg.ubicomp.droidguide.common.DroidGuideUser;
import br.ufmg.ubicomp.droidguide.eventservice.enums.EventState;
import br.ufmg.ubicomp.droidguide.eventservice.enums.EventType;
import br.ufmg.ubicomp.droidguide.eventservice.event.EventFilter;
import br.ufmg.ubicomp.droidguide.eventservice.event.EventFilterElement;
import br.ufmg.ubicomp.droidguide.eventservice.event.EventSource;
import br.ufmg.ubicomp.droidguide.eventservice.event.UserEvent;
import br.ufmg.ubicomp.droidguide.eventservice.exception.EventServiceError;
import br.ufmg.ubicomp.droidguide.eventservice.exception.EventServiceException;

/**
 * Event manager class responsible for managinng the events generated 
 * in the system.
 * @author wpjr
 *
 */
public class EventManager {

	private static final int QUEUE_SIZE = 1000;
	private Queue<UserEvent> events;
	private EventFilter eventFilter;
	private EventService service;
	
	/**
	 * singleton object
	 */
	private static EventManager theManager;
	
	public static EventManager getInstance()
	{
		if (theManager == null)
		{
			theManager = newInstance();
		}
		return theManager;
	}
	
	public static EventManager newInstance()
	{
		theManager = new EventManager();
		return theManager;
	}
	
	private EventManager() {
		events = new PriorityQueue<UserEvent>(QUEUE_SIZE);
		service = EventService.getInstance();
	}
	
	/**
	 * defines the event filter for the user
	 * @param filter the filter for the events
	 */
	public void defineEventFilter(EventFilter filter)
	{
		this.eventFilter = filter;
	}

	public void addEvent(UserEvent event)
	{
		events.add(event);
	}

	private void searchForEventsOfInterest(UserEvent event) {
		if (eventFilter != null)
		{
			for (EventFilterElement element: eventFilter.getElements())
			{
				if (element.getType().equals(event.getType()) && 
						event.getDescription().indexOf(element.getDescription()) != -1)
				{
					Logger logger = Logger.getLogger(getClass().getSimpleName());
					logger.info("Found event of interest!");
				}
			}
		}
	}

	private EventFilter getEventFilterForUser() {
		return eventFilter;
	}
	
	public boolean subscribeForEvent(UserEvent event) throws EventServiceException
	{
		verifyEventCanBeConsumed(event);
		events.add(event);
		return true;
	}

	private void verifyEventCanBeConsumed(UserEvent event)
			throws EventServiceException {
		if (!canEventBeConsumed(event))
		{
			throw new EventServiceException(EventServiceError.EVENT_CANNOT_BE_CONSUMED);
		}
	}

	private boolean canEventBeConsumed(UserEvent event)
	{
		return event.getState().canBeConsumed();
	}
	
	public Collection<UserEvent> getUserEvents()
	{
		return events;
	}
	
	public void clearEvents()
	{
		events.clear();
	}
	
	public void consumeEvent(UserEvent event, DroidGuideUser user) throws EventServiceException
	{
		verifyEventCanBeConsumed(event);
		service.notifyEventConsumed(event, user);
		events.remove(event);
	}
	
	public UserEvent createEvent(Calendar date, EventType eventType,
			String description, EventSource source, String data) {
		UserEvent event = new UserEvent();
		event.setDateTime(Calendar.getInstance());
		event.setDescription(description);
		event.setState(EventState.CREATED);
		event.setType(EventType.PROFILE);
		event.setSource(source);
		event.setData(data);
		return event;
	}
	
}